package com.ist412.pocke;

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.app.Dialog;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.RelativeLayout;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

/**
 * 
 * This activity allows the user to edit the details of a Workout. The user can add, edit, and
 * remove Exercises. The user can also add, edit, and remove Sets within Exercises.
 * <p>
 * The id for the Workout to edit is provided by the caller Intent under "slot".
 * 
 * @throws IllegalArgumentException	Thrown when an invalid slot is supplied
 * 
 * @author Rob
 * @version 1.2
 */
public class WorkoutAddEditActivity extends Activity implements OnClickListener {
	
	protected enum PopupTypes {	EXERCISE, SET }
	
	protected ArrayList<Exercise> 	_exercises;
	protected LinearLayout 			_llyExercises;
	protected Workout				_workout;
	protected int					_workoutslot; // supplied from WorkoutActivity
	protected final int				_PADDINGEXERCISE = 10;
	protected final int				_PADDINGSET = 30;
	protected final boolean[]		_EMPTYSCHEDULE = { false, false, false, false, false, false, false };
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		// Remove title & Make fullscreen
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
        WindowManager.LayoutParams.FLAG_FULLSCREEN);
        
		setContentView(R.layout.workout_addedit);
		
		MainActivity.loadData();
		
		_exercises 		= new ArrayList<Exercise>();
		_llyExercises 	= (LinearLayout) findViewById(R.id.workoutaddedit_llyExercises);
		
		EditText edtName 		= (EditText) findViewById(R.id.workoutaddedit_edtName);
		Button btnAddExercise	= (Button) findViewById(R.id.workoutaddedit_btnAddExercise);
		Button btnAddSave		= (Button) findViewById(R.id.workoutaddedit_btnAddSave);
		Button btnDelete		= (Button) findViewById(R.id.workoutaddedit_btnDelete);
		Button btnCancel		= (Button) findViewById(R.id.workoutaddedit_btnCancel);
		
		btnAddSave.setOnClickListener(this);
		btnDelete.setOnClickListener(this);
		btnCancel.setOnClickListener(this);
		btnAddExercise.setOnClickListener(new PopupHandler(PopupTypes.EXERCISE, false, -1, -1));
		
		Intent intent = getIntent();
		Bundle b = intent.getExtras();
		
		try {
			_workoutslot = b.getInt("slot", -1); // slot in MainActivity._workouts
		} catch (NullPointerException npe) {
			Log.e("Workout AE", "Received null slot from WorkoutActivity, defaulting to -1");
			_workoutslot = -1;
			npe.printStackTrace();
		}
		
		if (_workoutslot == -1) {
			_workout = new Workout();
			edtName.setText("");
		} else {
			_workout = MainActivity._workouts.get(_workoutslot);
			btnAddSave.setText("Save");
			edtName.setText(_workout.getName());
		}
		
		_exercises = _workout.getExercises();
		
		showExercises();
		
		// Fill in schedule data
		boolean[] schedule = _workout.getSchedule();
		
		if (!compareBoolArr(schedule, _EMPTYSCHEDULE)) {
			CheckBox chkSunday = (CheckBox) findViewById(R.id.workoutaddedit_chkSunday);
			CheckBox chkMonday = (CheckBox) findViewById(R.id.workoutaddedit_chkMonday);
			CheckBox chkTuesday = (CheckBox) findViewById(R.id.workoutaddedit_chkTuesday);
			CheckBox chkWednesday = (CheckBox) findViewById(R.id.workoutaddedit_chkWednesday);
			CheckBox chkThursday = (CheckBox) findViewById(R.id.workoutaddedit_chkThursday);
			CheckBox chkFriday = (CheckBox) findViewById(R.id.workoutaddedit_chkFriday);
			CheckBox chkSaturday = (CheckBox) findViewById(R.id.workoutaddedit_chkSaturday);
			
			ArrayList<CheckBox> dayCheckboxes = new ArrayList<CheckBox>();
			dayCheckboxes.add(chkSunday);
			dayCheckboxes.add(chkMonday);
			dayCheckboxes.add(chkTuesday);
			dayCheckboxes.add(chkWednesday);
			dayCheckboxes.add(chkThursday);
			dayCheckboxes.add(chkFriday);
			dayCheckboxes.add(chkSaturday);
			
			if (_workout.getHour() > 0 || _workout.getMinute() > 0) {
				for (int i = 0; i < schedule.length; i++) {
					if (schedule[i]) {
						dayCheckboxes.get(i).setChecked(true);
					}
				}
				
				EditText edtHour = (EditText) findViewById(R.id.workoutaddedit_edtHour);
				EditText edtMinute = (EditText) findViewById(R.id.workoutaddedit_edtMinute);
				
				edtHour.setText(Integer.toString(_workout.getHour()));
				edtMinute.setText(Integer.toString(_workout.getMinute()));
			}
		
		} // end if (exercise is not default (no schedule))
		
	} // end onCreate()
	
	@Override
	public void onResume() {
		super.onResume();
		
		// Clear menu
		refreshMenu();
	}
	
	@Override
	public void onClick(View v) {
		switch (v.getId()) {
			case R.id.workoutaddedit_btnAddSave:
				// Save
				if (saveWorkout()) {
					MainActivity.saveData();
					finish();
				}
				break;
			case R.id.workoutaddedit_btnDelete:
				removeWorkout();
				MainActivity.saveData();
				finish();
				break;
			case R.id.workoutaddedit_btnCancel:
				// Cancel
				finish();
				break;
		}
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	
	// Menu, Workout, and _exercise functions
	
	/**
	 * This clears the LinearLayout holding Exercise and Set information then calls showExercises()
	 */
	protected final void refreshMenu() {
		_llyExercises.removeAllViews();
		showExercises();
	}
	
	/**
	 * TODO Sort exercises based on name or exercise count, as specified by user
	 */
	protected final void sortExercises() {
		// This function sorts exercises
		// InsertionSort
		/*int i, j;
		String val;
		for (j = 1; j < _exercises.size(); j++) {
			for (i = j - 1; (i >= 0) && _exercises.get(i).getName())
		}*/
	}
	
	/**
	 * This function makes sure all the required information for the Workout
	 * object is entered, then it saves the Workout object.
	 * 
	 * @return	boolean signifying successful save
	 * 
	 * TODO Use SQLite and insert the Workout into the database
	 */
	protected final boolean saveWorkout() {	
		// 1. Push into workout exercises
		// TODO Add under id_workout when SQLite available
		
		EditText edtName = (EditText) findViewById(R.id.workoutaddedit_edtName);
		EditText edtHour = (EditText) findViewById(R.id.workoutaddedit_edtHour);
		EditText edtMinute = (EditText) findViewById(R.id.workoutaddedit_edtMinute);
		CheckBox chkSunday = (CheckBox) findViewById(R.id.workoutaddedit_chkSunday);
		CheckBox chkMonday = (CheckBox) findViewById(R.id.workoutaddedit_chkMonday);
		CheckBox chkTuesday = (CheckBox) findViewById(R.id.workoutaddedit_chkTuesday);
		CheckBox chkWednesday = (CheckBox) findViewById(R.id.workoutaddedit_chkWednesday);
		CheckBox chkThursday = (CheckBox) findViewById(R.id.workoutaddedit_chkThursday);
		CheckBox chkFriday = (CheckBox) findViewById(R.id.workoutaddedit_chkFriday);
		CheckBox chkSaturday = (CheckBox) findViewById(R.id.workoutaddedit_chkSaturday);
		
		ArrayList<CheckBox> dayCheckboxes = new ArrayList<CheckBox>();
		dayCheckboxes.add(chkSunday);
		dayCheckboxes.add(chkMonday);
		dayCheckboxes.add(chkTuesday);
		dayCheckboxes.add(chkWednesday);
		dayCheckboxes.add(chkThursday);
		dayCheckboxes.add(chkFriday);
		dayCheckboxes.add(chkSaturday);
		
		String wname = edtName.getText().toString();
		
		if (wname.length() > 0) {
			Workout w = new Workout(wname, _exercises);
			
			/*if (_newworkout) {
				MainActivity._workouts.add(w);
			} else {
				MainActivity._workouts.set(_workoutslot, w);
			}*/
			
			// Check for schedule
			boolean[] schedule = _EMPTYSCHEDULE.clone();
			int hour, minute;
			
			for (int i = 0; i < dayCheckboxes.size(); i++) {
				//Log.e("Workout AE", "Box checked: " + dayCheckboxes.get(i).isChecked());
				schedule[i] = dayCheckboxes.get(i).isChecked();
				//Log.e("Workout AE", "schedule[" + i + "]: " + schedule[i]);
			}
			
			//Log.e("Workout AE","Schedule: " + schedule);
			
			// Boxes are checked
			if (!compareBoolArr(schedule, _EMPTYSCHEDULE)) {
				hour = getIntIfEntered(edtHour);
				minute = getIntIfEntered(edtMinute);
				
				// All hours of the day, account for midnight
				if ((hour >= 0 && hour <= 23) || (hour == 24 && minute == 0)) {
					if (minute >= 0 & minute < 60) {
						w.setSchedule(schedule, hour, minute);
					} else {
						showToast("Invalid minute entered");
						edtMinute.requestFocus();
						return false;
					}
				} else{
					showToast ("Invalid hour entered");
					edtHour.requestFocus();
					return false;
				}
				
			} // end if (empty schedule)
			
			if (_workoutslot < 0) {
				MainActivity._workouts.add(w);
			} else {
				MainActivity._workouts.set(_workoutslot, w);
			}
			
			return true;
		} else {
			Toast.makeText(this, "Enter Workout Name", Toast.LENGTH_SHORT).show();
			return false;
		}
	}
	
	/**
	 * This function removes the currently selected Workout. 
	 */
	protected final void removeWorkout() {
		// TODO Implement SQLite in order to just use id_workout
		// This works because the slot in the main method is passed here from WorkoutActivity
		// Otherwise this would have to loop through all, trying to find a workout with a matching name + exercises
		//Toast.makeText(this, "Workout Deleted", Toast.LENGTH_SHORT).show();
		MainActivity._workouts.remove(_workoutslot);
	}
	
	/**
	 * This function will display all Exercises within the Workout and their sets within them.
	 * <p>
	 * First, it creates a RelativeLayout to hold the Exercise name and two buttons to Edit or delete it.
	 * Second, it creates a LinearLayout to hold more RelativeLayouts for each Set within the Exercise.
	 * Each Set has its own Edit and Delete buttons.
	 * An "Add Set" button appears below the last Set of each Exercise.
	 * <p>
	 * IDs:
	 * 101 - Exercise Name,	 102 - Exercise Edit,	103 - Exercise Delete
	 * 201 - Set Rep,		 202 - Set Edit, 		203 - Set Delete,		204 - Set Extra
	 * 
	 * @see	RelativeLayout, LinearLayout, ImageView
	 */
	protected final void showExercises() {
		// Views
		TextView tv;
		Button btn;
		ImageView imgEdit, imgDelete;
		RelativeLayout.LayoutParams rlp;
		RelativeLayout rly;
		LinearLayout lly, llyDetails;
		Exercise e;
		Set set;
		
		final int eEditID 		= 102;
		final int eDeleteID 	= 103;
		final int sRepID		= 201;
		final int sEditID		= 202;
		final int sDeleteID		= 203;
		final int sExtraID		= 204;
		
		// TODO Sort exercise list here
		
		if (_exercises.size() == 0) {
			tv = new TextView(this);
			tv.setText("No Exercises Added");
			tv.setTextSize(30f);
			_llyExercises.addView(tv);
		}
		
		// Display Exercise title, then all sets within
		for (int i = 0; i < _exercises.size(); i++) {
			
			// Display Exercise
			e = _exercises.get(i);
			
			// Layout that will hold llyDetails, btnEdit, and btnDelete for the Exercise
			rly = new RelativeLayout(this);
			//rly.setPadding(0, 10, 0, 10);
			rly.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT));
			
			// Delete Button
			imgDelete = new ImageView(this);
			imgDelete.setImageResource(R.drawable.icon_delete);
			imgDelete.setId(eDeleteID);
			imgDelete.setOnClickListener(new DeleteExerciseHandler(i));
			rlp = new RelativeLayout.LayoutParams(new LayoutParams(100,LayoutParams.WRAP_CONTENT));
			rlp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
			
			rly.addView(imgDelete, rlp);
			
			// TODO Try re-using IDs. They should go out of scope with each iteration pass
			
			// Edit Button
			imgEdit = new ImageView(this);
			imgEdit.setImageResource(R.drawable.icon_edit);
			imgEdit.setId(eEditID);
			imgEdit.setOnClickListener(new PopupHandler(PopupTypes.EXERCISE, true, i, -1));
			rlp = new RelativeLayout.LayoutParams(new LayoutParams(100, LayoutParams.WRAP_CONTENT));
			rlp.addRule(RelativeLayout.LEFT_OF, imgDelete.getId());
			rlp.addRule(RelativeLayout.CENTER_VERTICAL);
			
			rly.addView(imgEdit, rlp);
			
			/////////////////////////////////// Set up details left of buttons
			// LinearLayout to hold details
			llyDetails = new LinearLayout(this);
			llyDetails.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
			llyDetails.setOrientation(LinearLayout.VERTICAL);
			
			// Exercise Text Name
			tv = new TextView(this);
			tv.setText(e.getMuscleGroup() + " - " + e.getName());
			tv.setTextSize(20f);
			tv.setGravity(Gravity.CENTER);
			
			llyDetails.addView(tv);
			
			// Show Note
			if (e.getNote().length() > 0) {
				tv = new TextView(this);
				tv.setText("Note: " + e.getNote());
				tv.setTextSize(16f);
				tv.setGravity(Gravity.CENTER);
				llyDetails.addView(tv);
			}
			
			rlp = new RelativeLayout.LayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
			rlp.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
			rlp.addRule(RelativeLayout.LEFT_OF, imgEdit.getId());
			rly.addView(llyDetails, rlp);
			
			// Add to layout
			_llyExercises.addView(rly);
			
			// Prepare LinearLayout to show Exercise Sets
			// This will hold name
			lly = new LinearLayout(this);
			lly.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
			lly.setBackgroundColor(0x0C0C0C0);
			lly.setOrientation(LinearLayout.VERTICAL);
			lly.setPadding(0, 0, 0, _PADDINGEXERCISE);
			//lly.setPadding(20, 10, 0, 20);
			
			// TODO 1. get unique names
			// TODO 2. get sets for each name
			// TODO 3. sort sets by highest reps
			// TODO 4. print out name-set combos alphabetically
			
			// Display Sets from each Exercise
			for (int j = 0; j < _exercises.get(i).getSets().size(); j++) {
				
				set = _exercises.get(i).getSets().get(j);
				
				// New Row
				rly = new RelativeLayout(this);
				rly.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT));
				rly.setPadding(_PADDINGSET, 0, 0, 0);
				
				// Delete Button
				imgDelete = new ImageView(this);
				imgDelete.setImageResource(R.drawable.icon_delete);
				imgDelete.setId(sDeleteID);
				imgDelete.setOnClickListener(new DeleteSetHandler(i, j));
				rlp = new RelativeLayout.LayoutParams(new LayoutParams(100,LayoutParams.WRAP_CONTENT));
				rlp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
				
				rly.addView(imgDelete, rlp);
				
				// Edit Button
				imgEdit = new ImageView(this);
				imgEdit.setImageResource(R.drawable.icon_edit);
				imgEdit.setId(sEditID);
				imgEdit.setOnClickListener(new PopupHandler(PopupTypes.SET, true, i, j));
				rlp = new RelativeLayout.LayoutParams(new LayoutParams(100, LayoutParams.WRAP_CONTENT));
				rlp.addRule(RelativeLayout.LEFT_OF, imgDelete.getId());
				rlp.addRule(RelativeLayout.CENTER_VERTICAL);
				
				rly.addView(imgEdit, rlp);
				
				/////////////////////// Set up details left of buttons
				// LinearLayout to hold details
				llyDetails = new LinearLayout(this);
				llyDetails.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
				llyDetails.setOrientation(LinearLayout.VERTICAL);
				
				// Reps
				String setRepStr = "Set: " + Integer.toString((j + 1)) + " Reps: ";
				
				if (set.getExhaust()) {
					setRepStr += " Exhaust";
				} else {
					setRepStr += Integer.toString(set.getRep());
				}
				
				tv = new TextView(this);
				tv.setText(setRepStr);
				tv.setTextSize(20f);
				tv.setId(sRepID);
				llyDetails.addView(tv);
				
				// Training Weight & Note
				String extraString = "";
				
				if (set.getWeight() > 0) {
					extraString += "\nWeight: " + Integer.toString(set.getWeight());
				}
				
				if (set.getNote().length() > 0) {
					extraString += "\nNote: " + set.getNote();
				}
				
				// Only add note & PerTW if needed
				if (extraString.length() > 0) {
					tv = new TextView(this);
					tv.setText(extraString);
					tv.setTextSize(16f);
					llyDetails.addView(tv);
				}
				
				// Add llydetails
				rlp = new RelativeLayout.LayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
				rlp.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
				rlp.addRule(RelativeLayout.LEFT_OF, imgEdit.getId());
				rly.addView(llyDetails, rlp);
				
				// Add row
				lly.addView(rly);
			} // end for j
			
			// Add set button
			btn = new Button(this);
			btn.setText(R.string.addset);
			btn.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT));
			btn.setGravity(Gravity.CENTER);
			btn.setOnClickListener(new PopupHandler(PopupTypes.SET, false, i, -1));
			//btn.setPadding(0, 0, 20, 0);
			
			lly.addView(btn);
			
			_llyExercises.addView(lly);
		} // end for i
		
	} // end showExercises()
	
	// Exercise functions
	/**
	 * Adds Exercise to _exercises
	 * 
	 * @param e	Exercise object to add
	 */
	protected final void addExercise(Exercise e) {
		_exercises.add(e);
	}
	
	/**
	 * Replaces Exercise in _exercises at given slot
	 * 
	 * @param exslot	Slot in _exercises to replace
	 * @param e			Exercise object being inserted
	 */
	protected final void editExercise(int exslot, Exercise e) {
		_exercises.set(exslot, e);
	}
	
	/**
	 * Removes Exercise from _exercises at given slot
	 * 
	 * @param exslot	Slot to remove Exercise
	 */
	protected final void removeExercise(int exslot) {
		_exercises.remove(exslot);
	}
	
	/**
	 * Creates a new PopupExercise object and calls its showDialog method. Values
	 * signaling new Exercise creation are sent to the PopupExercise object
	 */
	protected final void addExercisePopup() {
		PopupExercise popEx = new PopupExercise(false, -1);
		popEx.showDialog();
	}
	
	/**
	 * Creates a new PopupExercise object with edit flag set to true and
	 * an exercise slot provided.
	 * 
	 * @param exslot	Slot in _exercises to replace with new Exercise object
	 */
	protected final void editExercisePopup(int exslot) {
		PopupExercise popEx = new PopupExercise(true, exslot);
		popEx.showDialog();
	}
	
	// Set functions
	
	/**
	 * Adds a set to an exercise
	 * 
	 * @param set	Set object to add
	 * @param exslot	Exercise index to receive set
	 */
	protected final void addSet(Set set, int exslot) {
		//Log.e("Trace","_exercises.size(): " + _exercises.size() + " exslot: " + exslot);
		_exercises.get(exslot).getSets().add(set);
	}
	
	/**
	 * Replaces a given Exercise's Set with the supplied Set
	 * 
	 * @param set	Set to insert
	 * @param exslot	Exercise index to edit
	 * @param setslot	Set index to replace
	 */
	protected final void editSet(Set set, int exslot, int setslot) {
		_exercises.get(exslot).getSets().set(setslot, set);
	}
	
	/**
	 * Removes set from a specific exercise in _exercises
	 * 
	 * @param exslot	Exercise index to edit
	 * @param setslot	Set index to remove
	 */
	protected final void removeSet(int exslot, int setslot) {
		_exercises.get(exslot).getSets().remove(setslot);
	}
	
	protected final void addSetPopup(int exslot) {
		PopupSet popSet = new PopupSet(false, exslot, -1);
		popSet.showDialog();
	}
	
	/**
	 * Creates a new PopupSet object with edit flag set to true
	 * with exercise and set slots providees
	 * 
	 * @param exslot	Exericse slot
	 * @param setslot	Set slot
	 */
	protected final void editSetPopup(int exslot, int setslot) {
		PopupSet popSet = new PopupSet(true, exslot, setslot);
		popSet.showDialog();
	}
	
	protected final void showToast(String text) {
		Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
	}
	
	/**
	 * Attempts to convert entered String into an int
	 * @param edt	EditText widget to use
	 * @return	int conversion of string if successful, -1 otherwise
	 */
	private final int getIntIfEntered(EditText edt) {
		int ret = -1;
		
		if (edt.getText().toString().length() > 0) {
			try {
				ret = Integer.parseInt(edt.getText().toString());
			} catch (Exception e) { return 0; }
		} else {
			ret = -1;
		}
		
		return ret;
	}
	
	/**
	 * @param a
	 * @param b
	 * @return true if a and b have the same length & values
	 */
	private final boolean compareBoolArr(boolean[] a, boolean[] b) {
		if (a.length == b.length) {
			for (int i = 0; i < a.length; i++) {
				if (a[i] != b[i]) {
					return false;
				}
			}
		} else {
			return false;
		}
		
		return true;
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	
	/**
	 * Utility class to handle deletion of Exercises
	 * 
	 * @author Rob C
	 * @version 1.0
	 */
	private class DeleteExerciseHandler implements OnClickListener {
		
		private int _exslot;
		
		/**
		 * @param exslot	Index in _exercises to delete
		 */
		public DeleteExerciseHandler(int exslot) {
			_exslot = exslot;
		}
		
		@Override
		public void onClick(View v) {
			MainActivity._workouts.get(_workoutslot).getExercises().remove(_exslot);
			refreshMenu();
		}
	}
	
	/**
	 * Utility class to handle deletion of Sets
	 * 
	 * @author Rob C
	 * @version
	 */
	private class DeleteSetHandler implements OnClickListener {
		
		private int _exslot, _setslot;
		
		/**
		 * @param exslot	Exercise in which to delete the Set
		 * @param setslot	Set slot to delete
		 */
		public DeleteSetHandler(int exslot, int setslot) {
			_exslot = exslot;
			_setslot = setslot;
		}
		
		@Override
		public void onClick(View v) {
			_exercises.get(_exslot).getSets().remove(_setslot);
			refreshMenu();
		}
	}
	
	/**
	 * Utility class to handle creation of PopupExercise and PopupSet in their edit and
	 * create modes.
	 * 
	 * @author Rob C
	 * @version 1.0
	 */
	private class PopupHandler implements OnClickListener {
		
		private PopupTypes 	_type;
		private boolean 	_edit;
		private int 		_exslot, _setslot;
		
		/**
		 * @param type	PopupTypes to handle EXERCISE or SET
		 * @param edit	boolean to signify edit or add mode
		 * @param exslot	exercise slot to edit
		 * @param setslot	set slot to edit
		 */
		public PopupHandler(PopupTypes type, boolean edit, int exslot, int setslot) {
			_type 		= type;
			_edit		= edit;
			_exslot 	= exslot;
			_setslot 	= setslot;
		}
		
		@Override
		public void onClick(View v) {
			if (_type == PopupTypes.EXERCISE) {
				if (_edit) {
					editExercisePopup(_exslot);
				} else {
					addExercisePopup();
				}
			} else if (_type == PopupTypes.SET) {
				if (_edit) {
					editSetPopup(_exslot, _setslot);
				} else {
					addSetPopup(_exslot);
				}
			}
		} // end onClick()
	} // end inner class PopupHandler
	
	/**
	 * Utility class to wrap a Dialog. Handles creating and editing Exercise objects.
	 * <p>
	 * It is a known bug that spinners will call their setOnItemSelectedListener as soon as they are initialized
	 * to combat this issue, _SPINNER_EVENTS represents the number of spinners in the form and _spinnerInitCount
	 * represents the number of times the setOnItemSelectedListeners were called before
	 * 
	 * @author Rob C
	 * @version 1.0
	 */
	private class PopupExercise implements OnClickListener {
		
		private final Dialog	_d;
		private boolean 		_edit;
		private int 			_exslot;
		private Button			_btnAddSave;
		private Spinner			_spnMuscleGroup, _spnExercise;
		
		/**
		 * @param edit	Signals whether or not an Exercise object is being edited
		 * @param exslot	Index in _exercises to replace if editing
		 */
		public PopupExercise(boolean edit, int exslot) {
			// Get edit information if existent
			_edit 				= edit;
			_exslot 			= exslot;
			
			// Pop up add exercise
			_d = new Dialog(WorkoutAddEditActivity.this, R.style.dialogstyle);
			_d.setContentView(R.layout.exercise_addedit);
			
			_btnAddSave			= (Button) _d.findViewById(R.id.exerciseaddedit_btnAddSave);
			Button btnDelete	= (Button) _d.findViewById(R.id.exerciseaddedit_btnDelete);
			Button btnCancel	= (Button) _d.findViewById(R.id.exerciseaddedit_btnCancel);
			
			_spnMuscleGroup 	= (Spinner) _d.findViewById(R.id.exerciseaddedit_spnMuscleGroup);
			_spnExercise 		= (Spinner) _d.findViewById(R.id.exerciseaddedit_spnName);
			
			_btnAddSave.setOnClickListener(this);
			btnDelete.setOnClickListener(this);
			btnCancel.setOnClickListener(this);
			
			setSpinners();
			
			// Setup form based on edit or create
			if (_edit) {
				_d.setTitle("Edit Exercise");
				EditText edtNote = (EditText) _d.findViewById(R.id.exerciseaddedit_edtNote);
				edtNote.setText(_exercises.get(_exslot).getNote());
				
				
				String mGroup = _exercises.get(_exslot).getMuscleGroup();
				String exName = _exercises.get(_exslot).getName();
				
				ArrayAdapter myAdap = (ArrayAdapter) _spnMuscleGroup.getAdapter(); //cast to an ArrayAdapter
				int spinnerPosition = myAdap.getPosition(mGroup);
				//set the default according to value
				_spnMuscleGroup.setSelection(spinnerPosition);
				
				// Update Exercise Spinner in order to see types of exercises
				setExerciseSpinner(mGroup);
				
				myAdap = (ArrayAdapter) _spnExercise.getAdapter();
				spinnerPosition = myAdap.getPosition(exName);
				//Log.e("Workout AE", "Trying to target set with name: " + _exercises.get(_exslot).getName());
				_spnExercise.setSelection(spinnerPosition);
				
				//
				_btnAddSave.setText(R.string.save);
			} else {
				// New
				_d.setTitle("Add Exercise");
				
				_spnExercise.setVisibility(View.GONE);
				_btnAddSave.setEnabled(false);
				btnDelete.setVisibility(View.GONE);
				
				
			} // end if .. else (edit)
			
		} // end constructor popupExercise()
		
		public void showDialog() {
			_d.show();
		}
		
		// TODO Find out how to override onDismiss to call refreshMenu(), or figure out appropriate activity function
		
		@Override
		public void onClick(View v) {
			switch(v.getId()) {
			case R.id.exerciseaddedit_btnAddSave:
				// 1. Check required fields are filled
				Spinner spnMuscleGroup 	= (Spinner) _d.findViewById(R.id.exerciseaddedit_spnMuscleGroup);
				Spinner spnName 		= (Spinner) _d.findViewById(R.id.exerciseaddedit_spnName);
				EditText edtNote		= (EditText) _d.findViewById(R.id.exerciseaddedit_edtNote);
				
				String muscleGroup 	= spnMuscleGroup.getSelectedItem().toString();
				String name 		= spnName.getSelectedItem().toString();
				String note			= "";
				
				if (edtNote.getText().toString().length() > 0) {
					note = edtNote.getText().toString();
				} else {
					note = "";
				}
				
				//Exercise e = new Exercise(name, set, rep);
				
				Exercise e = new Exercise();
				e.setMuscleGroup(muscleGroup);
				e.setName(name);
				e.setNote(note);
				
				if (_edit) {
					e.setSets(_exercises.get(_exslot).getSets());
					editExercise(_exslot,e);
				} else {
					addExercise(e);
				}
				
				refreshMenu();
				_d.dismiss();
				break;
			case R.id.exerciseaddedit_btnDelete:
				removeExercise(_exslot);
				refreshMenu();
				_d.dismiss();
				break;
			case R.id.exerciseaddedit_btnCancel:
				_d.dismiss();
				break;
			} // end switch (v.getID())
		} // end onClick()
		
		/**
		 * Grabs available MuscleGroups and pushes them into the muscle group spinner. The onItemSelected handler
		 * for the muscle group spinner is defined here.
		 * 
		 * TODO Grab muscle groups through SQLite
		 */
		protected final void setSpinners() {
			List<String> spinnerValues = new ArrayList<String>();
	        
	        // TODO Replace this with values retrieved from Muscle SQL
	        String[] sampleMuscleGroups = getResources().getStringArray(R.array.musclegroups);
	        
	        for (String s : sampleMuscleGroups) {
	        	spinnerValues.add(s);
	        }
	        
	        ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>(WorkoutAddEditActivity.this, R.layout.spinner_item, spinnerValues);
	        _spnMuscleGroup.setAdapter(spinnerArrayAdapter);
			
			_spnMuscleGroup.setOnItemSelectedListener(new OnItemSelectedListener() {
			    @Override
			    public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
			    	//Log.e("Trace","MuscleGroup selected.");
			        _spnExercise.setVisibility(View.VISIBLE);
	        		
	        		//Log.e("Workout AE","Exercise selected, muscle group: " + _spnMuscleGroup.getSelectedItem().toString()	+ " | name: " + _spnExercise.getSelectedItem().toString());
	        		
	        		ArrayList<String> spinnerValues = new ArrayList<String>();
	        		ArrayAdapter<String> spinnerArrayAdapter;
	        		String selMG = "";
	        		
	        		try {
	        			selMG = _spnMuscleGroup.getSelectedItem().toString();
	        			//Log.e("Workout AE","selMG: '" + selMG + "'");
	        		} catch (Exception e) {
	        			e.printStackTrace();
	        			//Log.e("Workout AE", "Problem converting selected muscle group to string.");
	        			_d.dismiss();
	        			finish();
	        		}
	        		
	        		setExerciseSpinner(selMG);
	        		
	        		_btnAddSave.setEnabled(true);
			    } // end spnMuscleGroup setOnItemSelected()

			    @Override
			    public void onNothingSelected(AdapterView<?> parentView) {
			        //
			    }
			}); // end spnMuscleGroup.setOnItemSelectedListener
		} // end setSpinners()
		
		/**
		 * Fills the spinner which contains exercises for the currently selected musclegroup. This function
		 * is separate from setSpinners() because it is called within the constructor in order to
		 * find the currently selected exercise when editing an exercise.
		 * <p>
		 * This is called as soon as the form opens, as a side-effect of initialization of a spinner
		 * in the android language.
		 * 
		 * @param muscleGroup	The name of the muscle group whose exercises are filling the form
		 * 
		 * TODO Call these through SQLite
		 */
		private final void setExerciseSpinner(String muscleGroup) {
			List<String> spinnerValues = new ArrayList<String>();
			ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>(WorkoutAddEditActivity.this, R.layout.spinner_item, spinnerValues);
	        _spnExercise.setAdapter(spinnerArrayAdapter);
			String[] exercises = {"debugtestitem"};
    		
			if (muscleGroup.equals("Abs")) {
				exercises = getResources().getStringArray(R.array.exercises_abs);
			} else if (muscleGroup.equals("Back")) {
				exercises = getResources().getStringArray(R.array.exercises_back);
			} else if (muscleGroup.equals("Biceps")) {
				exercises = getResources().getStringArray(R.array.exercises_biceps);
			} else if (muscleGroup.equals("Chest")) {
				exercises = getResources().getStringArray(R.array.exercises_chest);
			} else if (muscleGroup.equals("Forearm")) {
				exercises = getResources().getStringArray(R.array.exercises_forearm);
			} else if (muscleGroup.equals("Glutes")) {
				exercises = getResources().getStringArray(R.array.exercises_glutes);
			} else if (muscleGroup.equals("Hamstring")) {
				exercises = getResources().getStringArray(R.array.exercises_hamstring);
			} else if (muscleGroup.equals("Quads")) {
				exercises = getResources().getStringArray(R.array.exercises_quads);
			} else if (muscleGroup.equals("Shoulder")) {
				exercises = getResources().getStringArray(R.array.exercises_shoulder);
			} else if (muscleGroup.equals("Triceps")) {
				exercises = getResources().getStringArray(R.array.exercises_triceps);
			}
    		
    		//Log.e("Workout AE","selMG: " + selMG + " | Exercises length: " + exercises.length);
    		
    		if (exercises.length > 0) {
    			//Log.e("Workout AE","Exercises length greater than 0, filling spinnerValues.");
    			// Fill exercise spinner
    			for (String s : exercises) {
    				spinnerValues.add(s);
    			}
    			
    			// Add custom exercises
    			for (Exercise e : MainActivity._exercises) {
    				if (e.getMuscleGroup().equals(muscleGroup)) {
    					spinnerValues.add(e.getName());
    				}
    			}
    			
    			spinnerArrayAdapter = new ArrayAdapter<String>(WorkoutAddEditActivity.this, R.layout.spinner_item, spinnerValues);
    			_spnExercise.setAdapter(spinnerArrayAdapter);
    			
    		} else {
    			// Failed to load array, throw exception
    			try {
    				throw new IllegalArgumentException("Failed to populate sample exercises based on muscle group.");
    			} catch (IllegalArgumentException iae) {
    				iae.printStackTrace();
    				Log.e("Workout AE", "Failed to populate sample exercises based on muscle group."); 
    				_d.dismiss();
    				finish(); 
				}
    		}
		} // end setExerciseSpinner()
		
	} // end inner class PopupExercise
	
	/**
	 * Utility class which wraps a Dialog. Handles creating and editing sets.
	 * 
	 * @author Rob C
	 * @version 1.0
	 */
	private class PopupSet implements OnClickListener {
		
		private final Dialog 	_d;
		private boolean 		_edit;
		private int 			_exerciseslot, _setslot;
		private Exercise		_e;
		private Set				_set;
		
		/**
		 * @param edit	Whether or not an object is being edited
		 * @param exerciseslot	Slot in _exercises that is being edited
		 * @param setslot Slot in _exercises.getSets() that is being edited
		 */
		public PopupSet(boolean edit, int exerciseslot, int setslot) {
			_edit 			= edit;
			_exerciseslot 	= exerciseslot;
			_setslot		= setslot;
			
			// Pop up add exercise
			_d = new Dialog(WorkoutAddEditActivity.this, R.style.dialogstyle);
			_d.setContentView(R.layout.set_addedit);
			
			if (_edit) {
				_d.setTitle("Edit Set");
			} else {
				_d.setTitle("Add Set");
			}
			
			TextView txtExName	= (TextView) _d.findViewById(R.id.setaddedit_txtExerciseName);
			Button btnAddSave	= (Button)   _d.findViewById(R.id.setaddedit_btnAddSave);
			Button btnDelete	= (Button)   _d.findViewById(R.id.setaddedit_btnDelete);
			Button btnCancel	= (Button)   _d.findViewById(R.id.setaddedit_btnCancel);
			CheckBox chkExhaust = (CheckBox) _d.findViewById(R.id.setaddedit_chkExhaust);
			
			btnAddSave.setOnClickListener(this);
			btnDelete.setOnClickListener(this);
			btnCancel.setOnClickListener(this);
			chkExhaust.setOnClickListener(this);
			
			txtExName.setText(_exercises.get(_exerciseslot).getName());
			
			if (_edit) {
				/*Log.e("PopupAddHandler", "Edit: " + _edit + " | _exerciseslot: " + _exerciseslot);
				Log.e("PopupAddHandler", "_exercises.size(): " + _exercises.size());*/
				
				_e 		= _exercises.get(_exerciseslot);
				_set 	= _e.getSets().get(_setslot);
				
				// Fill fields with information
				EditText edtRep		= (EditText) _d.findViewById(R.id.setaddedit_edtRep);
				EditText edtWeight	= (EditText) _d.findViewById(R.id.setaddedit_edtWeight);
				EditText edtNote	= (EditText) _d.findViewById(R.id.setaddedit_edtNote);
				
				if (_set.getExhaust()) {
					chkExhaust.setChecked(true);
					edtRep.setEnabled(false);
				} else {
					edtRep.setText(Integer.toString(_set.getRep()));
				}
				
				
				if (_set.getWeight() > 0) {
					edtWeight.setText(Integer.toString(_set.getWeight()));
				} 
				
				if (_set.getNote().length() > 0) {
					edtNote.setText(_set.getNote());
				}
				
				btnAddSave.setText("Save");
				
			} else {
				btnDelete.setVisibility(View.GONE);
			}
			
		} // end constructor
		
		public void showDialog() {
			_d.show();
		}
		
		// TODO Find out how to override onDismiss to call refreshMenu(), or figure out appropriate activity function
		
		@Override
		public void onClick(View v) {
			switch(v.getId()) {
			case R.id.setaddedit_btnAddSave:
				// 1. Check required fields are filled
				CheckBox chkExhaust = (CheckBox) _d.findViewById(R.id.setaddedit_chkExhaust);
				EditText edtRep		= (EditText) _d.findViewById(R.id.setaddedit_edtRep);
				EditText edtWeight	= (EditText) _d.findViewById(R.id.setaddedit_edtWeight);
				EditText edtMinute	= (EditText) _d.findViewById(R.id.setaddedit_edtMinute);
				EditText edtSecond	= (EditText) _d.findViewById(R.id.setaddedit_edtSecond);
				EditText edtNote	= (EditText) _d.findViewById(R.id.setaddedit_edtNote);
				
				//String 	note = "";
				int 	rep = 0, weight = 0, min = 0, sec = 0, time = 0;
				boolean exhaust = false;
				String	note = "";
				
				// Required Fields
				if (getIntIfEntered(edtRep) > 0 || chkExhaust.isChecked()) {
					try {
						if (chkExhaust.isChecked()) {
							//Log.e("PopupAddHandler","Exhaust chosen");
							rep		= 0;
							exhaust = true;
						} else if (edtRep.getText().toString().length() > 0) {
							//Log.e("PopupAddHandler","Reps added");
							rep = Integer.parseInt(edtRep.getText().toString());
						} else {
							//Log.e("PopupAddHandler","Neither reps nor exhaust");
							throw new Exception();
						}
					} catch (Exception e) {
						Toast.makeText(v.getContext(), "Failed to add exercise", Toast.LENGTH_SHORT).show();
						return;
					}
					
					// Get optional fields
					weight 	= getIntIfEntered(edtWeight);
					min 	= getIntIfEntered(edtMinute);
					sec 	= getIntIfEntered(edtSecond);
					
					time = (min * 60000) + (sec * 1000);
					
					if (edtNote.getText().toString().length() > 0) {
						try {
							note = edtNote.getText().toString();
						} catch (Exception e) { note = ""; }
					}
				} else {
					Toast.makeText(WorkoutAddEditActivity.this, "Enter Reps", Toast.LENGTH_SHORT).show();
					return;
				} // end if .. else (rep or exhaust)
				
				// If set is nonexistent, check and add rep || add rep
				if (_set == null) {
					_set = new Set(rep);
				} else {
					_set.setRep(rep);
				}
				
				_set.setExhaust(exhaust);
				_set.setWeight(weight);
				_set.setTime(time);
				_set.setNote(note);
				
				// 2. Edit _exercises
				if (_edit) {
					// handle edit
					editSet(_set, _exerciseslot, _setslot);
				} else {
					addSet(_set, _exerciseslot);
				}
				
				refreshMenu();
				_d.dismiss();
				break;
			case R.id.setaddedit_btnDelete:
				removeSet(_exerciseslot, _setslot);
				refreshMenu();
				_d.dismiss();
				break;
			case R.id.setaddedit_btnCancel:
				_d.dismiss();
				
				break;
			case R.id.setaddedit_chkExhaust:
				chkExhaust 	= (CheckBox) _d.findViewById(R.id.setaddedit_chkExhaust);
				edtRep 		= (EditText) _d.findViewById(R.id.setaddedit_edtRep);
				
				if (chkExhaust.isChecked()) {
					edtRep.setText("Exhaust");
					edtRep.setEnabled(false);
				} else {
					edtRep.setEnabled(true);
					if (_edit) {
						rep = _set.getRep();
						edtRep.setText(Integer.toString(rep));
					} else {
						edtRep.setText("");
					}
				}
			} // end switch (v.getID())
		} // end onClick()
	} // end inner class PopupSet
	
} // end class WorkoutAddActivity